package com.j2eefast.flowable.bpm.service.impl;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.j2eefast.common.core.page.Query;
import com.j2eefast.common.core.utils.PageUtil;
import com.j2eefast.common.core.utils.ResponseData;
import com.j2eefast.common.core.utils.ToolUtil;
import com.j2eefast.flowable.bpm.entity.BpmModelEntity;
import com.j2eefast.flowable.bpm.entity.CompleteTaskEntity;
import com.j2eefast.flowable.bpm.entity.BpmTaskEntity;
import com.j2eefast.flowable.bpm.entity.output.FlowElementUserTaskEntity;
import com.j2eefast.flowable.bpm.enums.CommentTypeEnum;
import com.j2eefast.flowable.bpm.mapper.BpmTaskMapper;
import com.j2eefast.flowable.bpm.service.FlowableProcessInstanceService;
import com.j2eefast.flowable.bpm.service.IFlowableTaskService;
import com.j2eefast.flowable.bpm.utils.BpmConstant;
import com.j2eefast.flowable.bpm.utils.FlowableUtils;
import com.j2eefast.framework.utils.UserUtils;
import org.apache.ibatis.annotations.Param;
import org.flowable.bpmn.model.*;
import org.flowable.engine.ProcessEngine;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.flowable.engine.runtime.DataObject;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.DelegationState;
import com.j2eefast.framework.utils.Constant;
import org.flowable.task.api.Task;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * <p></p>
 *
 * @author: yhli
 * @date: 2020-04-25 14:38
 * @web: http://www.j2eefast.com
 * @version: 1.0.1
 */
@Service
public class FlowableTaskServiceImpl extends BaseProcessService implements IFlowableTaskService {

    @Resource
    private BpmTaskMapper bpmTaskMapper;
    @Autowired
    protected RuntimeService runtimeService;
    @Autowired
    protected FlowableProcessInstanceService flowableProcessInstanceService;


    @Override
    public PageUtil findApplyingTasksPage(Map<String, Object> params) {
        Page<BpmTaskEntity> page = bpmTaskMapper.findApplyingTasksPage(new Query<BpmTaskEntity>(params).getPage(),
                (String) params.get("userId"),
                (String) params.get(Constant.SQL_FILTER));
        return new PageUtil(page);
    }

    @Override
    public PageUtil findApplyedTasksPage(Map<String, Object> params) {
        Page<BpmTaskEntity> page = bpmTaskMapper.findApplyedTasksPage(new Query<BpmTaskEntity>(params).getPage(),
                (String) params.get("userId"),
                (String) params.get(Constant.SQL_FILTER));
        page.getRecords().forEach(bpmTask -> {
            bpmTask.setConsuming(DateUtil.formatBetween(bpmTask.getDuration()));
        });
        return new PageUtil(page);
    }

    /**
     * 根据id获取流程数据
     *
     * @param taskId
     * @return
     */

    @Override
    public BpmTaskEntity getTasksByTaskId(@Param("taskId") String taskId) {
        return bpmTaskMapper.getTasksByTaskId(taskId);
    }

    /**
     * 审批任务
     *
     * @param params 参数
     * @return
     */
    @Override
    @Transactional
    public ResponseData complete(CompleteTaskEntity params) {
        //1. 先判断是否有实例ID
        if (ToolUtil.isNotEmpty(params.getProcessInstanceId())
                && ToolUtil.isNotEmpty(params.getTaskId())) {
            String taskId = params.getTaskId();
            FlowElementUserTaskEntity defKey = nextFlowNode(taskId);
            //2.查看当前任务是存在 使用flowable 方法查询
            TaskEntity taskEntity =
                    (TaskEntity) taskService.createTaskQuery().taskId(taskId).singleResult();

            if (ToolUtil.isNotEmpty(taskEntity)) {
                //3.委派处理
                if (DelegationState.PENDING.equals(taskEntity.getDelegationState())) {
                    //3.1生成历史记录
                    TaskEntity task = this.createSubTask(taskEntity, params.getUserId());
                    taskService.complete(task.getId());
                    taskId = task.getId();
                    //3.2执行委派
                    taskService.resolveTask(params.getTaskId(), params.getVariables());
                } else {
                    //3.1修改执行人 其实我这里就相当于签收了
                    taskService.setAssignee(params.getTaskId(), params.getUserId());
                    //3.2执行任务
                    taskService.complete(params.getTaskId(), params.getVariables());
                    //4.处理加签父任务
                    String parentTaskId = taskEntity.getParentTaskId();
                    if (ToolUtil.isNotEmpty(parentTaskId)) {
                        String tableName = managementService.getTableName(TaskEntity.class);
                        String sql = "select count(1) from " + tableName + " where PARENT_TASK_ID_=#{parentTaskId}";
                        long subTaskCount = taskService.createNativeTaskQuery().sql(sql).parameter("parentTaskId", parentTaskId).count();
                        if (subTaskCount == 0) {
                            Task task = taskService.createTaskQuery().taskId(parentTaskId).singleResult();
                            //处理前后加签的任务
                            taskService.resolveTask(parentTaskId);
                            if (BpmConstant.AFTER_ADDSIGN.equals(task.getScopeType())) {
                                taskService.complete(parentTaskId);
                            }
                        }
                    }
                }
//                Task aa=  taskService.createTaskQuery().taskDefinitionKey(id).singleResult();
//                taskService.setAssignee(aa.getId(),params.getUserId());
                //Task task = taskService.createTaskQuery().processInstanceId(params.getProcessInstanceId()).singleResult();
                if (!defKey.getIsEndvent()) {
                    // 获取下一节点
                    Task entity = taskService.createTaskQuery().processInstanceId(params.getProcessInstanceId()).taskDefinitionKey(defKey.getId()).singleResult();
                    //增加下一节点审批人信息
                    taskService.setAssignee(entity.getId(), params.getFlowNextReviewerAssignee());
                }
                String type = params.getType() == null ? CommentTypeEnum.SP.toString() : params.getType();
                //5.生成审批意见
                this.addComment(taskId, params.getUserId(), params.getProcessInstanceId(), type, params.getMessage());

                return ResponseData.success("审批成功");
            } else {
                return ResponseData.error("20001", "没有次任务,请确认!");
            }
        } else {
            return ResponseData.error("20001", "传入参数错误,请确认参数是否正确!");
        }
    }

    /**
     * 获取任务节点
     *
     * @param taskId 任务id
     */
    @Override
    public FlowElementUserTaskEntity nextFlowNode(String taskId) {
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        ExecutionEntity ee = (ExecutionEntity) runtimeService.createExecutionQuery()
                .executionId(task.getExecutionId()).singleResult();
        // 当前审批节点
        String crruentActivityId = ee.getActivityId();
        BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
        FlowNode flowNode = (FlowNode) bpmnModel.getFlowElement(crruentActivityId);
        List<SequenceFlow> allFlowables = FlowableUtils.getElementOutgoingFlows(flowNode);
        FlowElement next = null;
        for (SequenceFlow sequenceFlow : allFlowables) {
            FlowElement targetFlowElement = sequenceFlow.getTargetFlowElement();
            if (targetFlowElement instanceof ExclusiveGateway) {
                next = setExclusiveGateway(targetFlowElement);
            } else if (targetFlowElement instanceof UserTask) {
                next = targetFlowElement;
            }else if (targetFlowElement instanceof EndEvent) {
                FlowElementUserTaskEntity task1 = null;
                task1.setIsEndvent(true);
                return task1;
            }
        }

        FlowElementUserTaskEntity task1 = (FlowElementUserTaskEntity) next;
        task1.setIsEndvent(false);
        return task1;
    }

    /**
     * 获取当前节点信息
     * @param taskId
     * @return
     */
    @Override
    public UserTask newFlowable(String taskId) {
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        ExecutionEntity ee = (ExecutionEntity) runtimeService.createExecutionQuery()
                .executionId(task.getExecutionId()).singleResult();
        // 当前审批节点
        String crruentActivityId = ee.getActivityId();
        BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
        FlowNode flowNode = (FlowNode) bpmnModel.getFlowElement(crruentActivityId);
        // 输出连线
        List<SequenceFlow> outFlows = flowNode.getOutgoingFlows();
        for (SequenceFlow sequenceFlow : outFlows) {
                FlowElement sourceFlowElement = sequenceFlow.getSourceFlowElement();
                System.out.println("当前节点: id=" + sourceFlowElement.getId() + ",name=" + sourceFlowElement.getName());
                return (UserTask)sourceFlowElement;

        }
        return null;
    }

    private FlowElement setExclusiveGateway(FlowElement targetFlow) {
        //排他网关，获取连线信息
        List<SequenceFlow> targetFlows = ((ExclusiveGateway) targetFlow).getOutgoingFlows();
        for (SequenceFlow sequenceFlow : targetFlows) {
            //目标节点信息
            FlowElement targetFlowElement = sequenceFlow.getTargetFlowElement();
            if (targetFlowElement instanceof UserTask) {
                return targetFlowElement;
            } else if (targetFlowElement instanceof EndEvent) {
                return targetFlowElement;
            } else if (targetFlowElement instanceof ServiceTask) {
                return targetFlowElement;
            } else if (targetFlowElement instanceof ExclusiveGateway) {
                //递归寻找
                return setExclusiveGateway(targetFlowElement);
            } else if (targetFlowElement instanceof SubProcess) {
                return targetFlowElement;
            }
        }
        return null;
    }

    public void getActivity(String taskId) {
        ExecutionEntity ee =
                (ExecutionEntity) taskService.createTaskQuery().taskId(taskId).singleResult();
        // ExecutionEntity ee = (ExecutionEntity) runtimeService.createExecutionQuery().executionId(task.getExecutionId()).singleResult();
// 当前审批节点
        String crruentActivityId = ee.getActivityId();
        BpmnModel bpmnModel = repositoryService.getBpmnModel(ee.getProcessDefinitionId());
        FlowNode flowNode = (FlowNode) bpmnModel.getFlowElement(crruentActivityId);
        // 输出连线
        List<SequenceFlow> outFlows = flowNode.getOutgoingFlows();
        for (SequenceFlow sequenceFlow : outFlows) {
            // 下一个审批节点
            FlowElement targetFlow = sequenceFlow.getTargetFlowElement();
            List<SequenceFlow> data = FlowableUtils.getElementOutgoingFlows(targetFlow);
            String id = data.get(0).getId();
        }
    }

    @Override
    public boolean isSuspended(String processInstanceId) {
        boolean flag = true;
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        if (processInstance != null) {
            flag = !processInstance.isSuspended();
        }
        return flag;
    }

    //	@Override
//	public void tuihui(CompleteTaskEntity params){
//		// 获取当前节点的activityId,即xml中每个标签的ID
//		String currentActivityId = execution.getCurrentActivityId();
//		List<Task> list1 = taskService.createTaskQuery().processInstanceId(params.getProcessInstanceId()).list();
//		//
//		taskService.addComment(params.getTaskId(), params.getProcessInstanceId(), params.getMessage());
//		BpmnModel bpmnModel = repositoryService.getBpmnModel(execution.getProcessDefinitionId());
//		FlowNode flowNode = (FlowNode)bpmnModel.getFlowElement(currentActivityId);
//		SequenceFlow sequenceFlow = flowNode.getIncomingFlows().get(0);
//		// 获取上一个节点的activityId
//		String sourceRef = sequenceFlow.getSourceRef();
//		// 流程回退到上一个节点，审批人继续审批
//		runtimeService.createChangeActivityStateBuilder()
//				.processInstanceId(processInstance.getProcessInstanceId())
//				.moveActivityIdTo(currentActivityId,sourceRef).changeState();
//
//	}

    /**
     * 获取并行流程
     *
     * @param params
     * @return
     */
    @Override
    public List<BpmTaskEntity> findApplyingParallelTasks(Map<String, Object> params) {
        List<BpmTaskEntity> lists = bpmTaskMapper.findApplyingParallelTasks((String) params.get("businessKey"),
                (String) params.get("userId"),
                (String) params.get(Constant.SQL_FILTER));
        return lists;
    }

    private Object getVal(ValuedDataObject valued, String valStr) {
        Object val = null;
        if (valued instanceof StringDataObject) {
            val = valStr;
        } else if (valued instanceof IntegerDataObject) {
            val = Integer.parseInt(valStr);
        } else if (valued instanceof LongDataObject) {
            val = Long.parseLong(valStr);
        } else if (valued instanceof DoubleDataObject) {
            val = Double.parseDouble(valStr);
        } else if (valued instanceof BooleanDataObject) {
            val = Boolean.parseBoolean(valStr);
        } else if (valued instanceof DateDataObject) {
            val = com.j2eefast.flowable.bpm.utils.DateUtil.string2date(valStr, com.j2eefast.flowable.bpm.utils.DateUtil.YYYY_MM_DD_HH_MM_SS);
        }
        return val;
    }

    /**
     * 获取流程变量
     *
     * @param taskId
     * @return
     */
    @Override
    public BpmModelEntity getVariables(String taskId) {
        //获得流程变量
        Map<String, Object> map = taskService.getVariables(taskId);
        BpmModelEntity result = JSONObject.parseObject(JSONObject.toJSONString(map), BpmModelEntity.class);
        return result;
    }

    /**
     * 根据TaskId获取当前流程信息
     *
     * @param taskId
     * @return
     */
    @Override
    public Map getDataObjects(String taskId) {
//        Map<String, DataObject> map = runtimeService.createExecutionQuery().
        return null;
    }


}
